package net.cloudcodex.client.character.presenter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.cloudcodex.client.CloudCodexEventBus;
import net.cloudcodex.client.cdo.CharacterCDO;
import net.cloudcodex.client.character.handler.TextBoxBaseKeyHandler;
import net.cloudcodex.client.character.view.CharacterDescriptionView;
import net.cloudcodex.client.character.view.CharacterDescriptionViewImpl;
import net.cloudcodex.client.character.view.CharactersNoteView;
import net.cloudcodex.client.character.view.CharactersView.Message;
import net.cloudcodex.client.util.rpc.SuccessCallback;
import net.cloudcodex.shared.dto.Result;
import net.cloudcodex.shared.dto.campaign.character.CharacterDescriptionDTO;
import net.cloudcodex.shared.dto.campaign.character.CharacterHeaderDTO;
import net.cloudcodex.shared.dto.campaign.character.CharacterNoteDTO;
import net.cloudcodex.shared.rpc.CampaignRPCAsync;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DecoratedPopupPanel;
import com.google.inject.Inject;
import com.mvp4g.client.annotation.Presenter;
import com.mvp4g.client.presenter.BasePresenter;

/**
 * 
 * 
 * @author ADaroussin
 */
@Presenter(view = CharacterDescriptionViewImpl.class, multiple = true)
public class CharacterDescriptionPresenter extends
		BasePresenter<CharacterDescriptionView, CloudCodexEventBus> {
	private final Message message;
	private CharacterCDO characterCDO;
	// private String nickName;
	private DecoratedPopupPanel popupPanel = new DecoratedPopupPanel(false,
			true);
	private CampaignRPCAsync campaignService;
	private List<CharacterHeaderDTO> characterHeaderDTOList;
	private Set<String> modifiedTextAreaTitleSet = new HashSet<String>();
	private boolean isOwner;
	private boolean isGameMaster;
	private Map<Long, Integer> notesViewIndexed = new HashMap<Long, Integer>();
	private List<CharactersNoteView> noteViews = new ArrayList<CharactersNoteView>();

	private Map<Long, CharacterNoteDTO> charactersNotesMap = new HashMap<Long, CharacterNoteDTO>();
	private Long ownerId;
	private Long byCharacterId;

	@Inject
	public CharacterDescriptionPresenter(Message pMessage,
			CampaignRPCAsync campaignService) {
		this.message = pMessage;
		this.campaignService = campaignService;
	}

	@Override
	public void bind() {
		TextBoxBaseKeyHandler privateKeyHandler = new TextBoxBaseKeyHandler();
		privateKeyHandler.setEventBus(eventBus);
		this.view.getPrivateDescriptionPanelKeyDownHandlers()
				.addKeyDownHandler(privateKeyHandler);
		this.view.getPrivateDescriptionPanelKeyUpHandlers().addKeyUpHandler(
				privateKeyHandler);

		TextBoxBaseKeyHandler publicKeyHandler = new TextBoxBaseKeyHandler();
		publicKeyHandler.setEventBus(eventBus);
		this.view.getPublicDescriptionPanelKeyDownHandlers().addKeyDownHandler(
				publicKeyHandler);
		this.view.getPublicDescriptionPanelKeyUpHandlers().addKeyUpHandler(
				publicKeyHandler);
		TextBoxBaseKeyHandler nameKeyHandler = new TextBoxBaseKeyHandler();
		nameKeyHandler.setEventBus(eventBus);
		TextBoxBaseKeyHandler iconKeyHandler = new TextBoxBaseKeyHandler();
		iconKeyHandler.setEventBus(eventBus);

		this.view.getNameTextBoxKeyUpHandlers().addKeyUpHandler(nameKeyHandler);
		this.view.getNameTextBoxKeyDownHandlers().addKeyDownHandler(
				nameKeyHandler);
		this.view.getIconTextBoxKeyUpHandlers().addKeyUpHandler(iconKeyHandler);
		this.view.getIconTextBoxKeyDownHandlers().addKeyDownHandler(
				iconKeyHandler);

		ValueChangeHandler<Boolean> valueChangeHandler = new ValueChangeHandler<Boolean>() {
			@Override
			public void onValueChange(ValueChangeEvent<Boolean> event) {
				CheckBox chxBx = (CheckBox) event.getSource();
				if (modifiedTextAreaTitleSet.contains(chxBx.getTitle())) {
					modifiedTextAreaTitleSet.remove(chxBx.getTitle());
				} else {
					modifiedTextAreaTitleSet.add(chxBx.getTitle());
				}
				setUpdateButtonEnable(!modifiedTextAreaTitleSet.isEmpty());
			}
		};

		this.view.getProfileCheckBox()
				.addValueChangeHandler(valueChangeHandler);
		this.view.getLockedCheckBox().addValueChangeHandler(valueChangeHandler);
		this.view.getDeadCheckBox().addValueChangeHandler(valueChangeHandler);

		view.getUpdateCharacterNotesButton().addClickHandler(
				new ClickHandler() {

					@Override
					public void onClick(ClickEvent event) {
						Long campaignId = characterCDO.getCampaignID();
						Long characterId = characterCDO.getId();
						String description = view.getChangedPublicDescription();
						String sheet = view.getChangedPrivateDescription();
						List<CharacterNoteDTO> notes = new ArrayList<CharacterNoteDTO>();
						Boolean isLocked = view.isLocked();
						Boolean isDead = view.isDead();

						for (CharactersNoteView notesView : noteViews) {
							CharacterNoteDTO changedNote = notesView
									.getChangedNotes();
							if (changedNote != null) {
								if (changedNote.getAuthor() == null) {
									changedNote.setAuthor(byCharacterId);
								}
								notes.add(changedNote);
								CharacterNoteDTO note = charactersNotesMap
										.get(byCharacterId);
							}
						}

						Map<Long, String> aliases = view.getAliases();

						campaignService
								.updateCharacterDescription(
										campaignId,
										characterId,
										byCharacterId,
										description,
										sheet,
										isDead,
										isLocked,
										notes,
										aliases,
										new SuccessCallback<Result<CharacterDescriptionDTO>>() {

											@Override
											public void onSuccess(
													Result<CharacterDescriptionDTO> result) {
												CharacterCDO characterCDO = CharacterDescriptionPresenter.this.characterCDO;
												characterCDO
														.setCharacterDescriptionDTO(result
																.getData());
												characterCDO
														.setPublicDescription(view
																.getChangedPublicDescription());
												refreshView();

												modifiedTextAreaTitleSet
														.clear();
												setUpdateButtonEnable(!modifiedTextAreaTitleSet
														.isEmpty());
											}
										});
					}
				});

	}

	public void initCharacterDescriptionPanel(CharacterCDO characterCDO) {
		this.characterCDO = characterCDO;
		this.isOwner = true;
		this.isGameMaster = false;
		view.clearButtonPanel();
		initView();
	}

	public void initCharacterDescriptionPopup(CharacterCDO characterCDO,
			boolean isOwner, boolean isGameMaster,
			List<CharacterHeaderDTO> characterHeaderDTOList) {
		this.characterHeaderDTOList = characterHeaderDTOList;
		this.characterCDO = characterCDO;
		this.isOwner = isOwner;
		this.isGameMaster = isGameMaster;
		this.ownerId = characterCDO.getOwnerId();

		view.clearButtonPanel();
		view.initPopupCancelButton();
		this.view.getPopupCancelButton().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				popupPanel.hide();
			}
		});
		initView();
		displayPopup();
	}

	private void initView() {
		view.setOwner(isOwner);
		view.setGameMaster(isGameMaster);
		view.setOwnerId(ownerId);
		notesViewIndexed.clear();
		noteViews.clear();
		charactersNotesMap.clear();
		initCharacterNoteMap();

		CharactersNotesPresenter personalNotePresenter = eventBus
				.addHandler(CharactersNotesPresenter.class);
		Long id = null;
		int index = 0;
		if (isGameMaster) {
			personalNotePresenter
					.addCharacterNote(charactersNotesMap.get(null));

		} else {
			personalNotePresenter.addCharacterNote(charactersNotesMap
					.get(byCharacterId));

		}
		personalNotePresenter.addAuthor(byCharacterId);
		personalNotePresenter.addCharacterID(id);
		personalNotePresenter.initview();
		notesViewIndexed.put(byCharacterId, index++);
		noteViews.add(personalNotePresenter.getView());

		if (characterHeaderDTOList != null) {
			for (CharacterHeaderDTO characterHeaderDTO : characterHeaderDTOList) {
				if (characterHeaderDTO.getOwner() != null) {

					id = characterHeaderDTO.getId();
					CharactersNotesPresenter characterNotesPresenter = eventBus
							.addHandler(CharactersNotesPresenter.class);

					CharacterNoteDTO noteDTO = charactersNotesMap.get(id);
					characterNotesPresenter.addCharacterNote(noteDTO);
					characterNotesPresenter.addCharacterID(id);
					characterNotesPresenter.addAuthor(id);
					characterNotesPresenter.initview();
					if (characterCDO.getId() != id) {
						characterNotesPresenter.addCharacter(
								characterHeaderDTO.getId(),
								characterHeaderDTO.getIcon(),
								characterHeaderDTO.getName());
					}

					notesViewIndexed.put(id, index++);

					noteViews.add(characterNotesPresenter.getView());
				}
			}
		}
		refreshCharacterDescriptionView();

	}

	private void initAdvancedInfosView() {
		this.view.isActive(characterCDO.isActive());
		this.view.addCharacterAdvancedInfos(characterCDO.isProfile(),
				characterCDO.isLocked(), characterCDO.isDead());

	}

	private void initCharacterNoteMap() {
		if (characterCDO.getNotes() != null) {
			for (CharacterNoteDTO characterNoteDTO : characterCDO.getNotes()) {
				charactersNotesMap.put(characterNoteDTO.getAuthor(),
						characterNoteDTO);
			}
		}
	}

	private void displayPopup() {

		popupPanel.setGlassEnabled(true);
		popupPanel.clear();
		popupPanel.add(view);
		popupPanel.center();
		popupPanel.show();
	}

	private void refreshCharacterDescriptionView() {
		view.initUpdateCharacterButton();
		view.addCharacter(characterCDO.getId(), characterCDO.getIcon(),
				characterCDO.getName());
		view.addCharacterAliases(characterCDO.getAliases());
		view.addCharacterPublicDescriptions(characterCDO.getPublicDescription());
		view.addCharacterPrivateDescriptions(characterCDO
				.getPrivateDescription());
		initChahacterNoteView();
		initAdvancedInfosView();
		view.initComponent();
	}

	/**
	 * 
	 */
	public void initChahacterNoteView() {
		List<CharactersNoteView> tempList = new ArrayList<CharactersNoteView>(
				noteViews);
		view.addPersonalNote(noteViews.get(0));

		if (notesViewIndexed.containsKey(characterCDO.getId())) {
			int idx = notesViewIndexed.get(characterCDO.getId());
			if (isGameMaster) {
				view.addPlayersNote(noteViews.get(idx));
			} else {
				view.addPersonalNote(noteViews.get(idx));

			}
			tempList.remove(idx);
		}
		if (!tempList.isEmpty())
			tempList.remove(0);
		for (CharactersNoteView charactersNoteView : tempList) {
			view.addPlayersNote(charactersNoteView);
		}
	}

	public void refreshView() {
		view.refreshPublicDescriptions(characterCDO.getPublicDescription());
		view.refreshPrivateDescriptions(characterCDO.getPrivateDescription());
		List<CharacterNoteDTO> noteDTOList = characterCDO.getNotes();
		if (noteDTOList != null) {
			for (CharacterNoteDTO characterNoteDTO : noteDTOList) {
				int indexView = notesViewIndexed.get(characterNoteDTO
						.getAuthor());
				CharactersNoteView noteView = noteViews.get(indexView);
				noteView.refreshNote(characterNoteDTO.getContent());
				charactersNotesMap.put(characterNoteDTO.getAuthor(),
						characterNoteDTO);
			}
		}

	}

	public void onUpdateButtonEnable(boolean isEnable, String textAreaID) {

		if (isEnable) {
			modifiedTextAreaTitleSet.add(textAreaID);
		} else {
			modifiedTextAreaTitleSet.remove(textAreaID);
		}
		setUpdateButtonEnable(!modifiedTextAreaTitleSet.isEmpty());
	}

	private void setUpdateButtonEnable(boolean enable) {
		view.setUpdateCharacterNotesButtonEnable(enable);
	}

	public Long getByCharacterID() {
		if (!isGameMaster) {
			return characterCDO.getId();
		}
		return null;
	}

	public void setByCharacterId(Long byCharacterId) {
		this.byCharacterId = byCharacterId;
	}
}
